﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Threading;
using System.Collections.Concurrent;
using System.Text.RegularExpressions;

namespace ParamSetCollection.Devices.CodeScanner
{
    class SerialScanner : Scanner
    {
        #region 内部类
        //用于延时使能扫描同样的码
        class CodeDelayUnit
        {
            public int Counter = 0;
            public string Code = "";

            public CodeDelayUnit()
            {

            }

            public CodeDelayUnit(string ciode)
            {

            }

            public bool CheckExist(string code)
            {
                if (code == Code)
                {
                    Counter = 0;
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        #endregion
        #region============================== 变量 ====================================
        public override event OnRawCodeEventHandler OnRawCodeEvent;

        public override event OnValidCodeEventHandler OnValidCodeEvent;

        public override event OnErrorMsgEventHandler OnErrorMsgEvent;

        Thread m_connetThre = null;
        Thread m_receiveThre = null;

        private Queue<string> barCodeList = new Queue<string>();//条码队列
        private Dictionary<string, CodeDelayUnit> CodeDelayDic = new Dictionary<string, CodeDelayUnit>();//延时读配方码队列

        string m_filterCode = "";

        int m_loopCount = 0;
        string m_codeBuf = "";
        string m_endMark = "\r\n";//结束符
        bool m_sameCodeFilter = true;

        private SerialPort serialPort = null;
        private int m_renewCount = 0;//需更新次数
        private bool m_start = false;
        private bool m_startConn = false;
        private string m_position = "";


        #endregion=====================================================================


        #region============================== 属性 ====================================
        public override string FilterCode { get { return m_filterCode; } set { m_filterCode = value; } }
        public override bool SameCodeFilter { get { return m_sameCodeFilter; } set { m_sameCodeFilter = value; } }
        #endregion=====================================================================


        #region============================= 内部函数 ================================
        private bool GetCode()
        {
            int count = Regex.Matches(m_codeBuf, m_endMark).Count;

            if (count > 0)
            {
                string[] ss = Regex.Split(m_codeBuf, m_endMark, RegexOptions.IgnoreCase);
                for (int i = 0; i < count; i++)
                {
                    if (ss[i] != "ERROR" && ss[i] != "ERROR::0%:0")
                    {
                        GetValidCode(ss[i]);
                    }
                }
                m_codeBuf = ss[ss.Length - 1];
                return true;
            }

            return false;
        }

        //获取有效数据
        private void GetValidCode(string str)
        {

            string[] delimiters = new string[] { m_endMark };
            string[] _code = str.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);




            for (int i = 0; i < _code.Length; i++)
            {
                string validCode = null;
                //判断是否符合筛选规则
                validCode = BarCodeFiltering(_code[i]);
                //byte[] b = Encoding.UTF8.GetBytes(validCode);
                if (validCode == null || validCode == "")
                {
                    continue;
                }

                OnRawCodeEvent?.Invoke(m_position, validCode);//原始码接收

                if (m_sameCodeFilter)
                {
                    //判断全码是否存在，已存在则丢弃，不存在则添加
                    if (CodeDelayDic.ContainsKey(validCode) == true)
                    {
                        CodeDelayDic[validCode].Counter = 0;
                        return;
                    }

                }
                else//不延时过滤
                {
                    barCodeList.Enqueue(validCode);
                }



            }

        }

        //判断是否有效条码
        private string BarCodeFiltering(string str)
        {
            if (m_filterCode == "")
            {
                return str;
            }

            else
            {

                //提取功能代码
                Regex re1 = new Regex(m_filterCode);
                try
                {
                    if (re1.IsMatch(str))
                    {
                        //stractIndex = i;
                        return str;
                    }
                }
                catch (Exception ex)
                {
                    OnErrorMsgEvent?.Invoke(m_position, "BarCodeFiltering error:" + ex.Message);
                    return null;
                }

                return null;
            }
        }

        //处理条码延时
        private void DelayCounter()
        {
            //延时自加，定时清除
            List<string> codeList = new List<string>();


            codeList.Clear();
            List<string> keyList = CodeDelayDic.Keys.ToList<string>();
            foreach (var item in keyList)
            {
                CodeDelayDic[item].Counter++;
                if (CodeDelayDic[item].Counter >= 500)//5 second
                {
                    codeList.Add(item);
                }
            }

            for (int i = 0; i < codeList.Count; i++)
            {
                CodeDelayDic.Remove(codeList[i]);
            }
        }
        #endregion====================================================================


        #region============================= 线程函数 ================================
        private void InitThread()
        {
            m_connetThre = new Thread(new ThreadStart(ConnThreadProcess));
            m_connetThre.IsBackground = true;
            m_connetThre.Start();

            m_receiveThre = new Thread(new ThreadStart(ReceiveThreadProcess));
            m_receiveThre.IsBackground = true;
            m_receiveThre.Start();
        }

        private void ConnThreadProcess()
        {
            while (m_start)
            {
                try
                {
                    if (this.serialPort != null && serialPort.IsOpen == false)
                    {

                        serialPort.Open();

                        Thread.Sleep(1000);
                    }

                    DelayCounter();

                    if (barCodeList.Count > 0)
                    {
                        try
                        {
                            string _str = barCodeList.Dequeue();
                            OnValidCodeEvent?.Invoke(m_position, _str);
                        }
                        catch (Exception ex)
                        {
                            OnErrorMsgEvent?.Invoke(m_position, "barCodeList.Dequeue error:" + ex.Message);
                        }
                    }
                }
                catch (Exception ex)
                {
                    OnErrorMsgEvent?.Invoke(m_position, "ConnThreadProcess error:" + ex.Message);
                    Thread.Sleep(5000);
                }
            }
        }

        private void ReceiveThreadProcess()
        {
            while (m_start)
            {
                if (serialPort.IsOpen == true)
                {

                    try
                    {
                        Thread.Sleep(10);
                        if (m_renewCount > 0)
                        {
                            m_renewCount--;
                            string _str = "";
                            _str = serialPort.ReadExisting();
                            if (_str != "")
                            {
                                if (m_codeBuf == "")
                                {
                                    m_loopCount = 0;
                                }
                                m_codeBuf += _str;

                                m_loopCount++;

                                //先检查是否有完整结束符，有则重新计数，否则清除字符缓存
                                if (GetCode() == true)
                                {

                                    m_loopCount = 0;
                                }
                                if (m_loopCount > 1000)
                                {

                                    m_codeBuf = "";
                                }

                            }
                            else
                            {
                                m_loopCount++;
                                if (m_loopCount > 1000)
                                {

                                    m_codeBuf = "";
                                }
                            }
                        }
                        else
                        {
                            m_codeBuf = "";
                        }
                    }
                    catch (Exception ex)
                    {
                        OnErrorMsgEvent?.Invoke(m_position, "ReceiveThreadProcess error:" + ex.Message);

                        Thread.Sleep(500);

                    }



                }
                else
                {
                    Thread.Sleep(1000);
                }
            }
        }
        #endregion====================================================================


        #region============================= 公开函数 ================================
        public SerialScanner(string position, int nameCode = 1, string endMark = "\r\n", bool sameCodeFilter = true,
            int rate = 9600, Parity pari = Parity.None, StopBits stbits = StopBits.One,
                    int timeout = 10
                    )
        {
            m_endMark = endMark;
            m_position = position;

            this.serialPort = new SerialPort();

            serialPort.PortName = "COM" + nameCode.ToString();
            serialPort.BaudRate = rate;
            serialPort.Parity = pari;
            serialPort.StopBits = stbits;
            serialPort.ReadTimeout = timeout;


            this.serialPort.DataReceived += serialPort_DataReceived;

            serialPort.Encoding = Encoding.UTF8;
        }

        public override void Start()
        {
            m_start = true;
            InitThread();
        }

        public override void Stop()
        {
            m_start = false;

            serialPort.Close();
        }

        public override void SoftTriggerStart(string cmd)
        {

        }

        public override void SoftTriggerStop(string cmd)
        {

        }
        #endregion====================================================================


        #region============================= 消息响应 ================================
        private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            m_renewCount++;
        }



        #endregion====================================================================
    }
}
